package wtws.message;

import java.nio.ByteBuffer;
import java.util.ArrayList;

import wtws.message.interf.TdwrProdMessage;
import wtws.util.ByteUtil;

public class PrecipitationProduct implements TdwrProdMessage {

	private static final long serialVersionUID = 1L;
	public static final int MSG_ID = 9236;
	public static final int MSG_LENGTH = 20;
	public static final String TITLE = "DFU Precipitation Product";
	private static final int MAX_GRID_SIZE = 80000;

	private static int encodeGrid(ArrayList<Short> grid, ArrayList<Byte> outByte) {
		ByteBuffer br = ByteBuffer.allocate(MAX_GRID_SIZE);

		Short previousGridValue = -1;
		Integer count = 0;
		int size = 0;
		for (Short value : grid) {
			if (value == previousGridValue || previousGridValue == -1) {
				previousGridValue = value;
			} else { // new value, save old value
				if (count < 16 && count > 0) {
					Integer x = (count << 4) + previousGridValue;
					br.put(x.byteValue());
					count = 0;
					size++;
				} else {
					while (count >= 256) {
						br.put(previousGridValue.byteValue());
						br.put((byte) 255);
						count -= 255;
						size++;
					}
					if (count > 0) {
						br.put(previousGridValue.byteValue());
						br.put(count.byteValue());
						count = 0;
						size++;
					}
				}
				previousGridValue = value;
			}
			count++;
		}
		if (count < 16 && count > 0) {
			Integer x = (count << 4) + previousGridValue;
			br.put(x.byteValue());
			count = 0;
			size++;
		} else {
			while (count >= 256) {
				br.put(previousGridValue.byteValue());
				br.put((byte) 255);
				count -= 255;
				size++;
			}
			if (count > 0) {
				br.put(previousGridValue.byteValue());
				br.put(count.byteValue());
				count = 0;
				size++;
			}
		}
		byte[] brArray = br.array();
		for (int i = 0; i < br.position(); i++) {
			outByte.add(brArray[i]);
		}
		return size;

	}

	private int messageId;
	private int messageLength;
	private int precipMapResolution;
	private int encoded;
	private int codeUnitCount;
	private float precipMapElevation;
	private long productGenerationTime;

	private byte[] pElements;

	public PrecipitationProduct(int precipMapResolution, float precipMapElevation, long productGenerationTime, ArrayList<Short> grid) {
		this.messageId = MSG_ID;
		this.encoded = 1;
		this.precipMapResolution = precipMapResolution;
		this.precipMapElevation = precipMapElevation;
		this.productGenerationTime = productGenerationTime;
		ArrayList<Byte> bList = new ArrayList<Byte>();
		this.codeUnitCount = encodeGrid(grid, bList);
		this.pElements = new byte[bList.size()];
		for (int i = 0; i < bList.size(); i++) {
			pElements[i] = bList.get(i);
		}
		this.messageLength = MSG_LENGTH + pElements.length;
	}

	@Override
	public byte[] toByteArray() {
		ByteBuffer br = ByteBuffer.allocate(messageLength);
		br.put(ByteUtil.to2Bytes(messageId));
		br.put(ByteUtil.to2Bytes(messageLength));
		br.put(ByteUtil.EMPTY_1B);
		br.put(ByteUtil.toByte(precipMapResolution));
		br.put(ByteUtil.toByte(encoded));
		br.put(ByteUtil.EMPTY_1B);
		br.put(ByteUtil.to2Bytes(codeUnitCount));
		br.put(ByteUtil.EMPTY_2B);
		br.putFloat(precipMapElevation);
		br.put(ByteUtil.to4Bytes(productGenerationTime));
		br.put(pElements);
		return br.array();
	}

	@Override
	public String getMessageTitle() {
		return TITLE;
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer();
		buf.append(messageId);
		buf.append(",");
		buf.append(codeUnitCount);
		buf.append(",");
		buf.append(ByteUtil.bytesToHex(pElements));
		return buf.toString();
	}

	public int getMessageId() {
		return messageId;
	}

	public void setMessageId(int messageId) {
		this.messageId = messageId;
	}

	public int getMessageLength() {
		return messageLength;
	}

	public void setMessageLength(int messageLength) {
		this.messageLength = messageLength;
	}

	public int getPrecipMapResolution() {
		return precipMapResolution;
	}

	public void setPrecipMapResolution(int precipMapResolution) {
		this.precipMapResolution = precipMapResolution;
	}

	public int getEncoded() {
		return encoded;
	}

	public void setEncoded(int encoded) {
		this.encoded = encoded;
	}

	public int getCodeUnitCount() {
		return codeUnitCount;
	}

	public void setCodeUnitCount(int codeUnitCount) {
		this.codeUnitCount = codeUnitCount;
	}

	public float getPrecipMapElevation() {
		return precipMapElevation;
	}

	public void setPrecipMapElevation(float precipMapElevation) {
		this.precipMapElevation = precipMapElevation;
	}

	public long getProductGenerationTime() {
		return productGenerationTime;
	}

	public void setProductGenerationTime(long productGenerationTime) {
		this.productGenerationTime = productGenerationTime;
	}

	public byte[] getpElements() {
		return pElements;
	}

	public void setpElements(byte[] pElements) {
		this.pElements = pElements;
	}

	public int getId() {
		return MSG_ID;
	}

}
